package emums

import (
	"encoding/json"
	"fmt"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	"reflect"
	"strconv"
)

// Enum 枚举接口
type Enum[T comparable] interface {
	// Description  枚举的描述
	Description() string
	// Values  返回一个包含所有枚举值的切片
	Values() []T
	// EnumItems 返回一个包含所有枚举值的切片
	EnumItems() []EnumItem[T]
	// Check 检查val是否枚举中一项
	Check(val T) bool
	// GetLabel  由val获取枚举值的描述
	GetLabel(val T) (string, bool)
	// ValueOf 根据名称返回对应的枚举值
	ValueOf(label string) (T, bool)
}

// EnumItem  枚举项
type EnumItem[T comparable] struct {
	Val   T
	Label string
}

// ------------enumHub-------------------------------------------------------------------

var enumHub = map[string]interface{}{}

// RegistEnum  注册枚举
func RegistEnum[T comparable](ename string, eval Enum[T]) {
	if v, exist := enumHub[ename]; exist {
		panic(fmt.Sprintf("ename[%s] already exist,existed enum is %+v,now is %+v", ename, v, eval))
	}
	enumHub[ename] = eval
}

// GetEnum 根据枚举名称获取枚举
func GetEnum[T comparable](ename string) (Enum[T], bool) {
	if v, exist := enumHub[ename]; exist {
		return v.(Enum[T]), true
	}
	return nil, false
}

//--------------enum validate------------------------------------------------------------------

const ENUM_TAG = "enum"

// AddEnumValidate 扩展validate标签
func AddEnumValidate(v *validator.Validate, trans ut.Translator) {
	//err := trans.Add(ENUM_TAG, "值{0}不符合枚举{1}的定义,或不存在{2}枚举定义", true)
	//fmt.Println(err)
	// 1.自己注册 自定义获取json标签值的中文翻译
	_ = v.RegisterTranslation(ENUM_TAG, trans, tranEnumRegis, tranEnumName)

	// 2. 注册校验规则
	v.RegisterValidation(ENUM_TAG, func(fl validator.FieldLevel) bool {
		//标签样例 enum=AnimalsEnum  fl.Param() 就是标签参数，即 AnimalsEnum
		enumName := fl.Param()

		if ei, ok := enumHub[enumName]; ok {
			// 字段值
			fval := fl.Field().Interface()
			if checkEnumVal(ei, fval) {
				return true
			} else {
				return false
			}

		} else {
			return false
		}
	})
}

func checkEnumVal(ei interface{}, fval any) bool {
	v := reflect.ValueOf(ei)
	for i, len := 0, v.NumField(); i < len; i++ { // 遍历所有字段
		field := v.Field(i) // 获取第i个字段的反射值对象
		//fmt.Printf("Field %d: %s = %v\n", i, v.Type().Field(i).Name, field.Interface()) // 打印字段名和值
		if fval == field.Interface() {
			return true
		}
	}

	return false
}

// 注册enum标签的翻译
func tranEnumRegis(ut ut.Translator) error {
	// {0} 占位符
	return ut.Add(ENUM_TAG, "字段{0}值{1}不符合枚举{2}的定义,或不存在{3}枚举定义", true)
}

// enum翻译函数
func tranEnumName(ut ut.Translator, fe validator.FieldError) string {
	//t, _ := ut.T("email0", fe.Field())
	//return t

	// {0} {1}占位符 是下面ut.T()里可变参数的索引
	t, _ := ut.T(ENUM_TAG, fe.Field(), ToString(fe.Value()), fe.Param(), fe.Param())
	return t
}

// any to string
func ToString(value any) string {
	// interface 转 string
	if value == nil {
		return ""
	}

	switch it := value.(type) {
	case string:
		return it
	case error:
		return it.Error()
	case float64:
		return strconv.FormatFloat(it, 'f', -1, 64)
	case float32:
		return strconv.FormatFloat(float64(it), 'f', -1, 64)
	case int:
		return strconv.Itoa(it)
	case uint:
		return strconv.Itoa(int(it))
	case int8:
		return strconv.Itoa(int(it))
	case uint8:
		return strconv.Itoa(int(it))
	case int16:
		return strconv.Itoa(int(it))
	case uint16:
		return strconv.Itoa(int(it))
	case int32:
		return strconv.Itoa(int(it))
	case uint32:
		return strconv.Itoa(int(it))
	case int64:
		return strconv.FormatInt(it, 10)
	case uint64:
		return strconv.FormatUint(it, 10)
	case []byte:
		return string(it)
	default:
		newValue, _ := json.Marshal(value)
		return string(newValue)
	}
}
